#include "soundmanager.h"
#include "resourcemanager.h"
#include <fmod.h> 
#include <fmod.hpp>
#include <string>
#include "fmod_errors.h"
#include "actor.h"
#include <iostream>
#include <assert.h>
#include <math.h>
#include "resource.h"
#include "boost/shared_ptr.hpp"

namespace core
{

		// static variables
		SoundManager* SoundManager::m_Single = NULL;
		

		// singelton
		SoundManager* SoundManager::GetInstance()
		{
				if(m_Single==0)
				{
						m_Single = new SoundManager();
						
				}

				return m_Single;
		}



		SoundManager::SoundManager()
		{
				//create & init sound system, right-handed coordinate 
				m_System = NULL;
				
		}

		

		//clean up, release fmod-system
		SoundManager::~SoundManager()
		{
			
				m_System->close(); 
				m_System->release();
				delete m_Single;
		}


		void SoundManager::Init( BootPtr p_Boot )
		{
				FMOD::System_Create( &m_System );

				//not using an actor as listener as defult
				m_actorAsListener = false;


				if( p_Boot->stereo )		m_System->setSpeakerMode( FMOD_SPEAKERMODE_STEREO );
				else										m_System->setSpeakerMode( FMOD_SPEAKERMODE_5POINT1);

				m_System->init( MAX_AUDIO_CHANNELS, FMOD_INIT_3D_RIGHTHANDED , 0 ); 
		
				
				//set volumes
				m_MasterSoundFxVolume = DEFAULT_SOUNDEFFECT_VOLUME;
				m_MasterMusicVolume = DEFAULT_MUSIC_VOLUME;

				//set listener to null
				m_ActorListener = NULL;

				//create channelgroup for all music samples, we need to store active music channels
				m_System->createChannelGroup( "music", &m_MusicChannelGroup );

				//soundgroup for soundfx 
				m_System->createSoundGroup( "soundEffects", &m_FxSoundGroup );


				//init up, posisiotn, direcvton -listener vectors
				m_ListenerUp.x = 0.0f; 
				m_ListenerUp.y = 1.0f;
				m_ListenerUp.z = 0.0f;

				m_ListenerForward.x = 0.0f; 
				m_ListenerForward.y = 0.0f;
				m_ListenerForward.z = 0.0f;

				m_ListenerPosition.x = 0.0f; 
				m_ListenerPosition.y = 0.0f;
				m_ListenerPosition.z = 0.0f;
				  
				//set up 3d listener attributes
				m_System->set3DListenerAttributes( 0, &m_ListenerPosition, 0, &m_ListenerForward, &m_ListenerUp );
		}



		//=====================
    // SetListener()
    //! Set an actor that will act as the listener,
    //=====================
		void SoundManager::SetListener( Actor& p_Actor )
		{
				m_ActorListener = &p_Actor;
				m_actorAsListener = true;
		}



		//=====================
    // SetListener()
    //! Set Listener  position and direction by vectors
    //=====================
		void SoundManager::SetListener( const Vector3& p_Position, const Vector3& p_Direction   )
		{
				
				m_actorAsListener = false;

				//set position
				m_ListenerPosition.x = p_Position.x;
				m_ListenerPosition.y = p_Position.y;
				m_ListenerPosition.z = p_Position.z;

				//set direction
				m_ListenerForward.x = p_Direction.x;
				m_ListenerForward.y = p_Direction.y;
				m_ListenerForward.z = p_Direction.z;

		}


		//=====================
    // Update()
    //! Updates listener attributes
    //! Must be called on every frame
    //!
    //=====================
		void SoundManager::update()
		{
				//set new m_ListenerPosition and m_ListenerForward 
				//if we use an  actor as listener, update 
				//listenere attributes from the actors pos and dir vectors
				if(m_actorAsListener)
				{
						m_ListenerForward.x = m_ActorListener->foward.x;
						m_ListenerForward.y = m_ActorListener->foward.y;
						m_ListenerForward.z = m_ActorListener->foward.z;

						m_ListenerPosition.x = m_ActorListener->pos.x;
						m_ListenerPosition.y = m_ActorListener->pos.y;
						m_ListenerPosition.z = m_ActorListener->pos.z;
						
				}

				//set new attributes
				m_Result = m_System->set3DListenerAttributes( 0, &m_ListenerPosition, 0, &m_ListenerForward, &m_ListenerUp );

				//update volume to sound fx group
				m_Result = m_FxSoundGroup->setVolume( m_MasterSoundFxVolume );

				//update system
				m_Result = m_System->update();
		}


		//=====================
    // PlayMusic()
    //!
    //! Returns a music id/handle.
    //!  
    //!  TODO:errorhandling
    //=====================
		void SoundManager::PlayMusic( AudioPtr p_Audio, int p_LoopCount )
		{
				//get sound from resource				
				FMOD::Sound* sound = p_Audio->GetSound();

				//validate loopcounter
				int loopcount = 0;

				if(p_LoopCount <= -1)
						loopcount = -1; 

				//set looping attribute
				 sound->setLoopCount(p_LoopCount);			

				

				//play the sound
				FMOD::Channel* musicChannel;
				m_System->playSound( FMOD_CHANNEL_FREE, sound, true, &musicChannel );				
				musicChannel->setVolume(m_MasterMusicVolume);			
				musicChannel->setPaused( false );

				//update fmodsystem
				m_System->update();
				
				//get the id of the channel, return it
				int channelIndex = 0;
				musicChannel->getIndex( &channelIndex );

				//put it in a channelgroup so we can access it later
				musicChannel->setChannelGroup( m_MusicChannelGroup );

				//return the id of the channel as a handle
				p_Audio->SetChannel( channelIndex );
		}


		//=====================
    // PlaySound()
    //! 
    //!  
    //=====================
		void SoundManager::PlaySound( const Vector3& p_Position, AudioPtr p_Audio )
		{
				//get sound object from the resource
				FMOD::Sound* sound = p_Audio->GetSound();

				//put the soundfix in the FxSoundGroup
				m_Result = sound->setSoundGroup( m_FxSoundGroup );
				

				//tempchannel
				FMOD::Channel* tempChannel = NULL;
					
				//play it, start as paused
				m_Result = m_System->playSound( FMOD_CHANNEL_FREE, sound, true, &tempChannel );
				

				//update channel , set positin for sound (from the actor's position)
				FMOD_VECTOR pos = { p_Position.x, p_Position.y, p_Position.z} ;
				m_Result = tempChannel->set3DAttributes( &pos , 0);
				
				tempChannel->setVolume(m_MasterSoundFxVolume);

				//unpause channel, start
				m_Result = tempChannel->setPaused( false );
				

				//update fmod system
				m_Result = m_System->update();							
		}

	

		//=====================
    // UnpausetMusic()
    //! Start a music sound by the musicid/handle
    //=====================
		void SoundManager::UnpauseMusic( AudioPtr p_Sound )
		{
				FMOD::Channel* playingChannel = NULL;
				m_Result = m_System->getChannel( p_Sound->GetChannel() , &playingChannel );

				m_Result = playingChannel->setPaused( false );
		}


		//=====================
    // StopMusic()
    //! Stop a playing music by the musicid/handle
    //=====================
		void SoundManager::StopMusic( AudioPtr p_Sound )
		{
				FMOD::Channel* playingChannel = NULL;
				m_Result = m_System->getChannel( p_Sound->GetChannel() , &playingChannel );

				m_Result = playingChannel->stop();
		}

		//=====================
    // StoppAllMusic()
    //! Stop all the playing music
    //=====================
		void SoundManager::StopAllMusic()
		{
				m_Result = m_MusicChannelGroup->stop();

		}
		
		//=====================
    // PauseMusic()
    //! Pause a playing music sound by musidId/handle
    //=====================
		void SoundManager::PauseMusic( AudioPtr p_Sound )
		{
				//get the requested channel
				FMOD::Channel* playingChannel = NULL;
				m_Result = m_System->getChannel( p_Sound->GetChannel() , &playingChannel );
				
				//pause the playing channel
				m_Result = playingChannel->setPaused( true );
		}



		//=====================
    // SetMasterFxVolume()
    //! Set the master volume for all soundfx sounds
    //=====================
		void SoundManager::SetMasterEffectVolume( int p_Percent )
		{
				if( p_Percent >= 100 )
						m_MasterSoundFxVolume = 1.0f;
				
				if( p_Percent <= 0 )
						m_MasterSoundFxVolume = 0.0f;
				
				m_MasterSoundFxVolume = ( (float)p_Percent ) / 100.0f ;
				m_FxSoundGroup->setVolume( m_MasterSoundFxVolume );
				
		}



		//=====================
    // SetMasterMusicVolume()
    //! Set the master volume for all music sounds
    //=====================
		void SoundManager::SetMasterMusicVolume( int p_Percent )
		{
				if( p_Percent >= 100 )
						m_MasterMusicVolume = 1.0f;
				
				if( p_Percent <= 0 )
						m_MasterMusicVolume = 0.0f;

				m_MasterMusicVolume = ( (float)p_Percent ) / 100.0f;	
				m_Result = m_MusicChannelGroup->overrideVolume(m_MasterMusicVolume);
			
		}



		
		//=====================
    // SetMuiscVolume()
    //! Set the volume for a playing music sound by musidId/handle
    //=====================
		void SoundManager::SetMuiscVolume( AudioPtr p_Sound , int p_VolumePercent )
		{
				//get the requested channel
				FMOD::Channel* playingChannel = NULL;
				m_Result = m_System->getChannel( p_Sound->GetChannel() , &playingChannel );

				float volume = 0.0f;

				if( p_VolumePercent >= 100 )
						volume = 1.0f;
				
				if( p_VolumePercent <= 0 )
						volume = 0.0f;

				volume = ( (float) p_VolumePercent ) / 100.0f ;
				
				//set volume for the playing channel
				m_Result = playingChannel->setVolume( volume );
				
		}



}

